package data

import (
    "database/sql"
    "fmt"
    "log"
    "os"
    "time"

    "github.com/gomodule/redigo/redis"
    _ "github.com/lib/pq"
)

const (
    defaultHost     = "localhost"
    defaultPort     = 5432
    defaultUser     = "postgres"
    defaultPassword = "postgres"
    defaultDBName   = "mmo"
    defaultRedisURL = "localhost:6379"
)

var (
    db        *sql.DB
    redisPool *redis.Pool
)

// GetDSN 获取数据库连接字符串
func GetDSN() string {
    host := os.Getenv("DB_HOST")
    if host == "" {
        host = defaultHost
    }
    
    port := os.Getenv("DB_PORT")
    if port == "" {
        port = fmt.Sprintf("%d", defaultPort)
    }
    
    user := os.Getenv("DB_USER")
    if user == "" {
        user = defaultUser
    }
    
    password := os.Getenv("DB_PASSWORD")
    if password == "" {
        password = defaultPassword
    }
    
    dbname := os.Getenv("DB_NAME")
    if dbname == "" {
        dbname = defaultDBName
    }
    
    return fmt.Sprintf("host=%s port=%s user=%s "+
        "password=%s dbname=%s sslmode=disable",
        host, port, user, password, dbname)
}

// InitDB 初始化数据库连接
func InitDB() error {
    var err error
    db, err = sql.Open("postgres", GetDSN())
    if err != nil {
        return err
    }
    
    // 测试连接
    err = db.Ping()
    if err != nil {
        return err
    }
    
    // 配置连接池
    db.SetMaxOpenConns(100)
    db.SetMaxIdleConns(10)
    db.SetConnMaxLifetime(time.Minute * 3)
    
    log.Println("Successfully connected to database!")
    return nil
}

// GetDB 获取数据库连接
func GetDB() *sql.DB {
    return db
}

// CloseDB 关闭数据库连接
func CloseDB() {
    if db != nil {
        db.Close()
        log.Println("Database connection closed")
    }
}

// GetRedisPool 获取Redis连接池
func GetRedisPool() *redis.Pool {
    if redisPool == nil {
        redisURL := os.Getenv("REDIS_URL")
        if redisURL == "" {
            redisURL = defaultRedisURL
        }
        
        redisPool = &redis.Pool{
            MaxIdle:     3,
            IdleTimeout: 240 * time.Second,
            Dial: func() (redis.Conn, error) {
                return redis.Dial("tcp", redisURL)
            },
        }
    }
    
    return redisPool
}

// 玩家数据操作
func SavePlayerData(playerID int64, data []byte) error {
    conn := GetRedisPool().Get()
    defer conn.Close()
    
    // 保存到Redis缓存
    _, err := conn.Do("SET", fmt.Sprintf("player:%d:data", playerID), data)
    if err != nil {
        log.Printf("Failed to save player data to Redis: %v", err)
    }
    
    // 异步保存到数据库
    go func() {
        _, err := GetDB().Exec(
            "INSERT INTO player_data (player_id, data, updated_at) VALUES ($1, $2, NOW()) "+
            "ON CONFLICT (player_id) DO UPDATE SET data = EXCLUDED.data, updated_at = EXCLUDED.updated_at",
            playerID, data)
        if err != nil {
            log.Printf("Failed to save player data to database: %v", err)
        }
    }()
    
    return err
}

// 加载玩家数据
func LoadPlayerData(playerID int64) ([]byte, error) {
    conn := GetRedisPool().Get()
    defer conn.Close()
    
    // 从Redis缓存加载
    data, err := redis.Bytes(conn.Do("GET", fmt.Sprintf("player:%d:data", playerID)))
    if err == nil {
        return data, nil
    }
    
    // 如果缓存中没有，从数据库加载
    if err == redis.ErrNil {
        var dbData []byte
        err = GetDB().QueryRow(
            "SELECT data FROM player_data WHERE player_id = $1", playerID).Scan(&dbData)
        if err != nil {
            if err == sql.ErrNoRows {
                return nil, nil
            }
            return nil, err
        }
        
        // 将数据存入缓存
        go func() {
            conn := GetRedisPool().Get()
            defer conn.Close()
            conn.Do("SET", fmt.Sprintf("player:%d:data", playerID), dbData)
        }()
        
        return dbData, nil
    }
    
    return nil, err
}    